世界太新,很多事物還沒有名字,必須用手指頭伸手去指。
— 賈西亞•馬奎茲《百年孤寂》
Clojure 從 2007 年由創始人 Rich Hickey 公開發表以來,至今已經經過十個年頭。經過十年歲月的演進,Clojure 程式語言已經被越來越多公司採用,也有許多優秀的開源專案選擇使用 Clojure,是成熟與實用的程式語言。
Clojure 是動態程式語言,意思是指在 Clojure 裡頭,撰寫者可以在執行時期隨時改變構成程式的元素,例如物件、型態或函式,擁有比靜態更多的彈性與自由。
除了是動態程式語言之外,Clojure 也是一個函數式程式語言。如果搜尋網路上函數式程式語言的定義,可以找出每個人都有不同的看法。但是基本的看法是不變的,那就是函式能夠被當成基本型態一樣自由地建立、可以當成另一個函式的參數傳遞、也可以被當成函式的返回值,傳遞給上層的函式呼叫者。
Clojure 屬於 LISP 程式語言家族的一員,亦即它們有相似的語法以及「程式如資料」設計理念。從外觀上看起來就是一堆括號與關鍵字組合而成。LISP 程式語法使用前置表示法,將運算元或函式名稱擺放在括號中的第一個位置,其他位置則擺放參數或運算子。有其他程式語言經驗的人初次遇見時,可能會因爲它相異於目前主流的語法而卻步,然而如果花點時間耐心學習,將會理解到 LISP 語法其實非常簡單,但是在簡單的語法之中還能有複雜的變化,搭配強大的巨集系統,足以構建複雜的大型軟體系統。
Clojure 也是一個寄宿在 JVM 的程式語言,利用 JVM 成熟的虛擬化以及動態編譯技術,和數以萬計爲 JVM 編寫的成熟函式庫,能夠開發穩定可靠的軟體系統。雖然也有使用 .NET 技術的 Clojure 可供使用,但是目前的成熟程度仍然無法與使用 JVM 技術的 Clojure 相比。
Clojure 另外一個特點則是提供了方便簡單的並行程式設計方法,讓撰寫程式的人不必再去處理複雜的並行問題,專心處理核心問題。搭配設計精巧的語言特性,撰寫程式的人亦可以簡單地將程式遷移到具備多核心處理器的環境之中,充分發揮多核心處理器平行運算的能力。
Clojure 還提供了豐富好用的資料結構,這些資料結構都是不可變以及持久存在的。不可變指的是一個資料結構一旦建立之後,就無法再修改它,必須再建立新的資料結構存放新的資料;持久存在則是 Clojure 在建立新資料時會參考舊資料的內容,從舊資料中分支出的新的資料結構。這樣的方法有效地利用了空間,並減少了重新建立資料的時間。
如果你是想要了解學習 Clojure 的讀者,這一系列的文章就是爲你而寫的。雖然這一系列文章是寫給初學 Clojure 的讀者,但是如果你有其他程式設計語言的經驗,例如物件導向程式語言 Python 或 Ruby,這一系列的文章便非常的適合你。如果你完全是一個程式設計語言的新手,建議你搭配其他市面上一般程式語言學習的書籍一起閱讀。
如果你已經是個非常有經驗的程式設計老手,想要鑽研 Clojure 內部結構或是精妙的設計手法,這一系列的文章並不適合你,建議你可以另外再去閱讀更專門的書籍。
建議的閱讀方式是從頭開始閱讀起,有助於循序地了解 Clojure 的整體樣貌,在文章之中亦會穿插示範用的程式碼或操作,希望閱讀的各位讀者都可以在電腦上親自輸入並觀察結果。除了藉由輸入程式碼體會 Clojure 程式的樣貌之外,更可以在輸入並執行的過程中,了解還有哪些知識需要再補強。
在閱讀此一系列文章時候,或許因爲與過往學習的程式語言不同,而有卡關不理解的地方。這時候請你放慢腳步並保持耐心,畢竟新的思維並不是那麼容易就可以體會,但是一旦了解之後,定是非常舒暢愉快。
還有就是不要害怕括號。Clojure 程式中有很多的括號,那其實是 LISP 程式語言家族表現程式碼的方法,非常的單純與簡潔。當你多花時間體會之後,你將會對這種程式語言的表現手法感到讚歎!搭配編輯工具的套件來使用,輸入或修改括號不再是繁瑣無趣的工作。
在本系列文章中,有時候會在命令列模式下輸入指令,例如:
$ java --version
其中的 $
符號代表命令列模式下的提示符號,是不需要實際輸入的,只有 $
符號之後的文字才需要輸入。
除了命令列的提示符號之外,本系列文章中還會讓讀者在 REPL 之下輸入程式碼,例如:
(+ 1 2)
;; => 2
分號在 Clojure 程式語言中代表的是註解區域的開頭,所有分號之後的文字將被忽略不會當作程式執行。在這裡表示 Clojure 程式運行之後的結果。
這裡將會假設讀者你已經有一臺電腦可以使用,並且電腦中搭載了你熟悉的編輯器。還會假設你不會害怕在命令列模式下操作,因爲有很多時候將會在命令列模式下輸入程式碼。
因爲 Clojure 寄宿在 JVM 之上,所以你使用的電腦需要安裝 Java,如果不確定你的電腦是否安裝了 Java,你可以在命令列下輸入:
$ java --version
如果出現類似以下的訊息,表示你的環境已經安裝了 Java,你可以到下一個步驟安裝 Leiningen:
java version "1.8.0_71"
Java(TM) SE Runtime Environment (build 1.8.0_71-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.71-b15, mixed mode)
Java 版本必須要在 1.6 以上才可正常運作。
如果沒有安裝 Java,請到 Java 官方網站 下載並安裝。
Leiningen 是 Clojure 的專案管理工具,類似 Java 中的 Maven 或 Node.js 中的 npm。首先到 Leiningen 官方網站 遵從指示安裝之後,在命令列上輸入以下指令:
$ lein --version
如果出現類似以下的訊息,代表你的 Leiningen 已經安裝成功:
Leiningen 2.8.1 on Java 1.8.0_71 Java HotSpot(TM) 64-Bit Server VM
請注意,第一次執行 Leiningen 時因爲還會下載額外的套件,所以需要比較多的時間,請耐心等待。
當你的電腦已經安裝了 Java 與 Leiningen 之後,便可以開始建立專案了。在命令列模式之下輸入:
$ lein new embracing-clojure
Leiningen 便會開始建立一個目錄名稱爲 embracing-clojure,目錄中已經預先放置了一些程式碼與專案的設定檔。再來切換到專案的目錄底下:
$ cd embracing-clojure
切換目錄之後,執行以下指令開啓 REPL:
$ lein repl
出現類似以下訊息就表示 REPL 已成功開啓:
nREPL server started on port 50753 on host 127.0.0.1 - nrepl://127.0.0.1:50753
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_71-b15
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=>
你可以試着在其中輸入程式碼 (+ 1 2)
並按下 Enter 按鍵,你將會看到以下的訊息:
nREPL server started on port 50753 on host 127.0.0.1 - nrepl://127.0.0.1:50753
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_71-b15
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> (+ 1 2)
3
user=>
REPL 是 Read Evaluation Print Loop 的簡稱,在 REPL 環境會將你輸入的程式碼讀入 (Read),對程式碼求值 (Eval) 取得結果之後,把結果輸出到顯示裝置 (Print),並一再地重複這一系列的動作 (Loop)。在 REPL 中不僅可以將腦中的想法一步步地輸入驗證,亦可以利用 REPL 測試已經寫好的程式碼,快速且即時的回應將使得程式更快的驗證,確保程式的正確。
恭喜你!你已經成功地執行了第一個 Clojure 程式!
從本篇文章中你已經知道 Clojure 的歷史與特性,知道它是建立在 JVM 上的語言並支持並行設計。也知道 Clojure 屬於 LISP 程式語言家族的一份子,還有 Clojure 的資料結構都是不可變的,不用再擔心哪邊的程式修改了不該修改的資料。
你也已經下載並安裝了 Java 與 Leiningen,利用 Leiningen 建立了第一個 Clojure 專案,還在 REPL 中輸入了第一個 Clojure 運算式。
還不賴吧?今天就先到這裡,下一篇文章再見囉!
(本篇文章同步刊登於 GitHub,歡迎在文章下方留言或發送 PR 給予建議與指教)